import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import re
from typing import List, Dict, Tuple, Optional


class TexParser:
    """TeX文件解析器，提取章节信息"""

    def __init__(self):
        # 用于查找章、节和小节的正则表达式
        self.chapter_pattern = re.compile(r'\\chapter\s*{([^{}]*(?:{[^{}]*}[^{}]*)*)}')
        self.section_pattern = re.compile(r'\\section\s*{([^{}]*(?:{[^{}]*}[^{}]*)*)}')
        self.subsection_pattern = re.compile(r'\\subsection\s*{([^{}]*(?:{[^{}]*}[^{}]*)*)}')

    def parse_file(self, file_path: str) -> Dict:
        """解析TeX文件并提取章、节和小节及其内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                content = file.read()

            # 移除LaTeX注释
            content = self._remove_comments(content)

            # 获取所有章及其位置
            chapter_positions = self._find_all_positions(content, self.chapter_pattern)

            # 如果没有找到章，则假设整个文件是一个章
            if not chapter_positions:
                chapter_positions = [("未命名章节", 0, 0)]

            chapters = []
            for i, (chapter_name, chapter_start, _) in enumerate(chapter_positions):
                # 确定本章结束的位置
                chapter_end = len(content)
                if i < len(chapter_positions) - 1:
                    chapter_end = chapter_positions[i + 1][1]

                chapter_content = content[chapter_start:chapter_end]

                # 查找本章中的所有节
                section_positions = self._find_all_positions(chapter_content, self.section_pattern)

                sections = []
                for j, (section_name, section_start, _) in enumerate(section_positions):
                    # 确定本节结束的位置
                    section_end = len(chapter_content)
                    if j < len(section_positions) - 1:
                        section_end = section_positions[j + 1][1]

                    section_content = chapter_content[section_start:section_end]

                    # 查找本节中的所有小节
                    subsection_positions = self._find_all_positions(section_content, self.subsection_pattern)

                    subsections = []
                    for k, (subsection_name, subsection_start, _) in enumerate(subsection_positions):
                        # 确定小节结束的位置
                        subsection_end = len(section_content)
                        if k < len(subsection_positions) - 1:
                            subsection_end = subsection_positions[k + 1][1]

                        subsection_content = section_content[subsection_start:subsection_end]
                        subsections.append({
                            'name': subsection_name,
                            'content': self._clean_content(subsection_content),
                            'number': f"{i + 1}.{j + 1}.{k + 1}"
                        })

                    # 提取直接属于节的内容（在任何小节之前）
                    direct_section_content = section_content
                    if subsection_positions:
                        direct_section_content = section_content[:subsection_positions[0][1]]

                    sections.append({
                        'name': section_name,
                        'content': self._clean_content(direct_section_content),
                        'number': f"{i + 1}.{j + 1}",
                        'subsections': subsections
                    })

                # 提取直接属于章的内容（在任何节之前）
                direct_chapter_content = chapter_content
                if section_positions:
                    direct_chapter_content = chapter_content[:section_positions[0][1]]

                chapters.append({
                    'name': chapter_name,
                    'content': self._clean_content(direct_chapter_content),
                    'number': f"第{i + 1}章",
                    'sections': sections
                })

            return {
                'file_name': os.path.basename(file_path),
                'file_path': file_path,
                'chapters': chapters
            }
        except Exception as e:
            messagebox.showerror("错误", f"解析文件 {file_path} 时出错: {str(e)}")
            return {
                'file_name': os.path.basename(file_path),
                'file_path': file_path,
                'sections': []
            }

    def _remove_comments(self, content: str) -> str:
        """从内容中删除LaTeX注释"""
        # 删除注释（从%到行尾）
        pattern = re.compile(r'(?<!\\)%.*?$', re.MULTILINE)
        return pattern.sub('', content)

    def _find_all_positions(self, content: str, pattern: re.Pattern) -> List[Tuple[str, int, int]]:
        """查找所有匹配项及其名称和位置"""
        matches = pattern.finditer(content)
        positions = []

        for match in matches:
            # 名称在组1中，起始位置是匹配的结束
            name = match.group(1).strip()
            start_pos = match.end()
            match_start = match.start()
            positions.append((name, start_pos, match_start))

        return positions

    def _clean_content(self, content: str) -> str:
        """清理提取的内容"""
        # 删除多余的空白和前导/尾随换行符
        content = content.strip()
        # 将多个换行符替换为单个换行符
        content = re.sub(r'\n\s*\n', '\n\n', content)
        return content


class FileManager:
    """文件管理器，处理文件操作"""

    def __init__(self):
        self.files = []  # 文件路径列表
        self.parser = TexParser()
        self.parsed_data = []  # 解析后的文件数据列表
        self.combined_data = None  # 合并后的数据

    def add_files(self, file_paths: List[str]) -> Tuple[int, List[str]]:
        """
        添加新的TeX文件到管理器

        返回:
            包含（添加的文件数，错误消息列表）的元组
        """
        added_count = 0
        errors = []

        for file_path in file_paths:
            if file_path.lower().endswith('.tex'):
                if file_path not in self.files:
                    try:
                        # 首先尝试打开文件以验证它存在且可读
                        with open(file_path, 'r', encoding='utf-8') as _:
                            pass

                        self.files.append(file_path)
                        parsed_data = self.parser.parse_file(file_path)
                        self.parsed_data.append(parsed_data)
                        added_count += 1
                    except Exception as e:
                        errors.append(f"文件 {os.path.basename(file_path)} 出错: {str(e)}")
                else:
                    errors.append(f"文件已添加: {os.path.basename(file_path)}")
            else:
                errors.append(f"不是TeX文件: {os.path.basename(file_path)}")

        # 重置合并数据
        self.combined_data = None

        return added_count, errors

    def add_folder(self, folder_path: str) -> Tuple[int, List[str]]:
        """
        将文件夹中的特定5个TeX文件添加到管理器
        严格只添加：1.tex、2.tex、3.tex、4.tex和conclusion.tex这5个文件

        参数:
            folder_path: 文件夹路径

        返回:
            包含（添加的文件数，错误消息列表）的元组
        """
        added_count = 0
        errors = []
        missing_files = []

        try:
            # 清除当前所有文件
            self.files = []
            self.parsed_data = []
            self.combined_data = None

            # 按顺序检查并添加特定的5个文件
            specific_files = ['1.tex', '2.tex', '3.tex', '4.tex', 'conclusion.tex']
            found_files = []

            for filename in specific_files:
                file_path = os.path.join(folder_path, filename)
                if os.path.exists(file_path) and os.path.isfile(file_path):
                    try:
                        with open(file_path, 'r', encoding='utf-8') as _:
                            pass

                        self.files.append(file_path)
                        parsed_data = self.parser.parse_file(file_path)
                        self.parsed_data.append(parsed_data)
                        added_count += 1
                        found_files.append(filename)
                    except Exception as e:
                        errors.append(f"文件 {filename} 读取错误: {str(e)}")
                else:
                    missing_files.append(filename)

            if not found_files:
                errors.append(f"文件夹 {folder_path} 中没有找到任何指定的文件")
            elif missing_files:
                errors.append(f"文件夹中缺少以下文件: {', '.join(missing_files)}")

        except Exception as e:
            errors.append(f"处理文件夹时出错: {str(e)}")

        return added_count, errors

    def _natural_sort_files(self, file_paths: List[str]) -> List[str]:
        """
        对文件路径进行自然排序

        文件名中的数字将被正确排序，例如 1.tex, 2.tex, 10.tex
        特殊文件如 introduction.tex 将排在前面，conclusion.tex 排在最后
        """
        # 定义特殊文件顺序
        special_files_order = {
            'introduction': -999,  # 排在最前面
            'abstract': -998,
            'preface': -997,
            'foreword': -996,
            'conclusion': 999,  # 排在最后面
            'appendix': 998,
            'references': 997,
            'bibliography': 996
        }

        def get_sort_key(path):
            # 获取文件名（不带扩展名）
            filename = os.path.basename(path)
            name_without_ext = os.path.splitext(filename)[0].lower()

            # 检查是否是特殊文件
            for special_name, order in special_files_order.items():
                if name_without_ext == special_name or name_without_ext.startswith(special_name):
                    return (order, name_without_ext)

            # 提取文件名中的数字部分
            digits = ''.join(c for c in name_without_ext if c.isdigit())

            # 如果文件名中包含数字，按数字排序
            if digits:
                return (int(digits), name_without_ext)

            # 否则按文件名排序
            return (500, name_without_ext)  # 500是一个中间值，让非数字非特殊文件排在中间

        return sorted(file_paths, key=get_sort_key)

    def remove_file(self, index: int) -> bool:
        """
        从管理器中删除文件

        返回:
            如果成功则为True，否则为False
        """
        if 0 <= index < len(self.files):
            self.files.pop(index)
            self.parsed_data.pop(index)
            self.combined_data = None  # 重置合并数据
            return True
        return False

    def move_file(self, from_index: int, to_index: int) -> bool:
        """
        将文件从一个位置移动到另一个位置

        返回:
            如果成功则为True，否则为False
        """
        if 0 <= from_index < len(self.files) and 0 <= to_index < len(self.files):
            file = self.files.pop(from_index)
            data = self.parsed_data.pop(from_index)

            self.files.insert(to_index, file)
            self.parsed_data.insert(to_index, data)
            self.combined_data = None  # 重置合并数据
            return True
        return False

    def process_all_files(self) -> dict:
        """
        处理所有文件并生成一个包含所有章节的合并数据结构

        返回:
            包含所有章节的合并数据字典
        """
        if not self.files:
            return {
                'chapters': []
            }

        # 如果已经有合并数据且文件没有变化，则返回缓存的数据
        if self.combined_data:
            return self.combined_data

        # 创建一个新的合并数据结构
        combined_chapters = []
        chapter_count = 0

        # 遍历所有文件
        for file_index, file_data in enumerate(self.parsed_data):
            file_chapters = file_data['chapters']

            # 添加每个文件的章
            for chapter in file_chapters:
                chapter_count += 1
                new_chapter = {
                    'name': chapter['name'],
                    'content': chapter['content'],
                    'number': f"第{chapter_count}章",
                    'file_index': file_index,
                    'sections': []
                }

                # 添加章中的所有节
                for section_index, section in enumerate(chapter['sections']):
                    new_section = {
                        'name': section['name'],
                        'content': section['content'],
                        'number': f"{chapter_count}.{section_index + 1}",
                        'subsections': []
                    }

                    # 添加节中的所有小节
                    for subsection_index, subsection in enumerate(section['subsections']):
                        new_subsection = {
                            'name': subsection['name'],
                            'content': subsection['content'],
                            'number': f"{chapter_count}.{section_index + 1}.{subsection_index + 1}"
                        }
                        new_section['subsections'].append(new_subsection)

                    new_chapter['sections'].append(new_section)

                combined_chapters.append(new_chapter)

        # 创建并缓存合并数据
        self.combined_data = {
            'chapters': combined_chapters
        }

        return self.combined_data

    def get_all_parsed_data(self) -> List[Dict]:
        """获取所有解析的文件数据"""
        return self.parsed_data

    def get_file_count(self) -> int:
        """获取管理器中的文件数量"""
        return len(self.files)


class DraggableListbox(tk.Listbox):
    """支持拖放重新排序条目的列表框"""

    def __init__(self, master, **kw):
        super().__init__(master, **kw)
        self.bind('<ButtonPress-1>', self.on_button_press)
        self.bind('<B1-Motion>', self.on_button_motion)
        self.bind('<ButtonRelease-1>', self.on_button_release)
        self.curindex = None
        self.drag_api_triggered = False

        # 绑定鼠标右键显示上下文菜单
        self.bind('<Button-3>', self.show_context_menu)
        self.context_menu = None

    def on_button_press(self, event):
        """处理按钮按下事件以开始拖动"""
        i = self.nearest(event.y)
        self.curindex = i

    def on_button_motion(self, event):
        """处理按钮移动事件进行拖动"""
        if self.curindex is not None:
            i = self.nearest(event.y)
            if i != self.curindex and not self.drag_api_triggered:
                # 移动项目
                self.drag_api_triggered = True
                self.event_generate("<<ItemReordered>>", data=(self.curindex, i))
                self.curindex = i
                self.drag_api_triggered = False

    def get_all_parsed_data(self) -> List[Dict]:
        """获取所有解析的文件数据"""
        return self.parsed_data

    def get_file_count(self) -> int:
        """获取管理器中的文件数量"""
        return len(self.files)

    def on_button_release(self, event):
        """处理按钮释放事件以结束拖动"""
        self.curindex = None

    def show_context_menu(self, event):
        """显示上下文菜单"""
        if not self.context_menu:
            return

        # 先选择鼠标点击位置的项目
        index = self.nearest(event.y)
        self.selection_clear(0, tk.END)
        self.selection_set(index)
        self.activate(index)

        # 显示上下文菜单
        try:
            self.context_menu.tk_popup(event.x_root, event.y_root)
        finally:
            # 释放菜单
            self.context_menu.grab_release()


class LatexHighlighter:
    """LaTeX语法高亮辅助类"""

    def __init__(self, text_widget):
        self.text_widget = text_widget

        # 配置标签
        font_size = 12  # 默认字体大小
        try:
            # 尝试从文本小部件获取字体大小
            font_str = self.text_widget['font']
            if isinstance(font_str, str) and ' ' in font_str:
                font_size = int(font_str.split(' ')[1])
        except:
            pass

        self.text_widget.tag_configure("command", foreground="blue")
        self.text_widget.tag_configure("environment", foreground="purple")
        self.text_widget.tag_configure("math", foreground="green")
        self.text_widget.tag_configure("comment", foreground="gray", font=("TkDefaultFont", font_size, "italic"))
        self.text_widget.tag_configure("bracket", foreground="red")

    def highlight(self):
        """对文本小部件应用LaTeX语法高亮"""
        content = self.text_widget.get("1.0", tk.END)

        # 清除现有标签
        for tag in ["command", "environment", "math", "comment", "bracket"]:
            self.text_widget.tag_remove(tag, "1.0", tk.END)

        # 高亮LaTeX命令
        self._highlight_pattern(r'\\[a-zA-Z]+', "command")

        # 高亮环境
        self._highlight_pattern(r'\\begin{[^}]*}|\\end{[^}]*}', "environment")

        # 高亮数学模式
        self._highlight_pattern(r'\$.*?\$|\$\$.*?\$\$', "math")

        # 高亮注释
        self._highlight_pattern(r'%.*', "comment")

        # 高亮括号
        self._highlight_pattern(r'{|}|\[|\]', "bracket")

    def _highlight_pattern(self, pattern, tag):
        """对所有匹配模式的文本应用标签"""
        # 从开始位置开始
        start_pos = "1.0"
        while True:
            # 查找下一个匹配项
            start_pos = self.text_widget.search(pattern, start_pos, tk.END, regexp=True)
            if not start_pos:
                break

            # 计算结束位置
            line, col = map(int, start_pos.split('.'))
            line_text = self.text_widget.get(f"{line}.0", f"{line}.end")
            match = re.search(pattern, line_text[col:])
            if not match:
                break

            end_pos = f"{line}.{col + match.end()}"

            # 应用标签
            self.text_widget.tag_add(tag, start_pos, end_pos)

            # 移动到下一个位置
            start_pos = end_pos


class TexVisualizerApp:
    """TeX可视化应用主类"""

    def __init__(self, root):
        self.root = root
        self.root.title("TeX 文件可视化器")
        self.root.geometry("1200x800")

        self.file_manager = FileManager()
        self.search_mode = "single"  # 默认为单文件搜索模式

        # 设置样式
        self.setup_styles()

        self.create_ui()

    def setup_styles(self):
        """设置ttk样式"""
        style = ttk.Style()
        style.configure("TButton", padding=6, relief="flat", background="#ccc")
        style.configure("TLabelframe", padding=10)

        # 为"开始解析"按钮创建特殊样式
        style.configure("Accent.TButton",
                        font=("TkDefaultFont", 10, "bold"),
                        background="#4CAF50",
                        foreground="black")
        style.map("Accent.TButton",
                  background=[('active', '#45a049')],
                  relief=[('pressed', 'sunken')])

    def create_ui(self):
        """创建主UI组件"""
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 添加菜单栏
        self.create_menu()

        # 文件操作框架
        file_ops_frame = ttk.LabelFrame(main_frame, text="文件操作", padding="10")
        file_ops_frame.pack(fill=tk.X, pady=5)

        # 文件操作按钮
        ttk.Button(file_ops_frame, text="添加文件", command=self.add_files_dialog).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_ops_frame, text="选择文件夹", command=self.add_folder_dialog).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_ops_frame, text="删除所选", command=self.remove_selected_file).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_ops_frame, text="上移", command=lambda: self.move_file(-1)).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_ops_frame, text="下移", command=lambda: self.move_file(1)).pack(side=tk.LEFT, padx=5)

        # "开始解析"按钮用粗体突出显示并使用不同颜色
        process_button = ttk.Button(file_ops_frame, text="开始解析", command=self.process_all_files, style="Accent.TButton")
        process_button.pack(side=tk.LEFT, padx=5)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # 分割视图: 左侧文件和章节，右侧内容
        paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        paned_window.pack(fill=tk.BOTH, expand=True, pady=5)

        # 左侧面板用于文件和章节
        left_panel = ttk.Frame(paned_window)
        paned_window.add(left_panel, weight=1)

        # 右侧面板用于内容显示
        right_panel = ttk.Frame(paned_window)
        paned_window.add(right_panel, weight=2)

        # 文件列表
        file_frame = ttk.LabelFrame(left_panel, text="TeX 文件", padding="10")
        file_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.file_listbox = DraggableListbox(file_frame, selectmode=tk.SINGLE)
        self.file_listbox.pack(fill=tk.BOTH, expand=True)
        self.file_listbox.bind('<<ListboxSelect>>', self.on_file_select)
        self.file_listbox.bind('<<ItemReordered>>', self.on_item_reordered)

        # 为文件列表框添加滚动条
        file_scrollbar = ttk.Scrollbar(file_frame, orient="vertical", command=self.file_listbox.yview)
        file_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.file_listbox.configure(yscrollcommand=file_scrollbar.set)

        # 章节/子章节树视图
        section_frame = ttk.LabelFrame(left_panel, text="章节 & 子章节", padding="10")
        section_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        # 添加章节搜索框
        search_frame = ttk.Frame(section_frame)
        search_frame.pack(fill=tk.X, pady=(0, 5))

        ttk.Label(search_frame, text="搜索:").pack(side=tk.LEFT, padx=(0, 5))
        self.search_var = tk.StringVar()
        self.search_var.trace_add("write", self.on_search_change)
        search_entry = ttk.Entry(search_frame, textvariable=self.search_var)
        search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 创建带滚动条的树视图
        tree_frame = ttk.Frame(section_frame)
        tree_frame.pack(fill=tk.BOTH, expand=True)

        self.section_tree = ttk.Treeview(tree_frame)
        self.section_tree["columns"] = ("number", "name")
        self.section_tree.column("#0", width=20, stretch=tk.NO)
        self.section_tree.column("number", width=50, anchor=tk.W)
        self.section_tree.column("name", width=200, anchor=tk.W)
        self.section_tree.heading("number", text="编号")
        self.section_tree.heading("name", text="名称")
        self.section_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.section_tree.bind('<<TreeviewSelect>>', self.on_section_select)

        # 为章节树添加滚动条
        section_scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=self.section_tree.yview)
        section_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.section_tree.configure(yscrollcommand=section_scrollbar.set)

        # 内容显示
        content_frame = ttk.LabelFrame(right_panel, text="内容", padding="10")
        content_frame.pack(fill=tk.BOTH, expand=True)

        # 添加字体大小控制
        font_frame = ttk.Frame(content_frame)
        font_frame.pack(fill=tk.X, pady=(0, 5))

        ttk.Label(font_frame, text="字体大小:").pack(side=tk.LEFT, padx=(0, 5))
        self.font_size = tk.IntVar(value=12)
        font_spinbox = ttk.Spinbox(font_frame, from_=8, to=24, textvariable=self.font_size, width=5)
        font_spinbox.pack(side=tk.LEFT)
        font_spinbox.bind('<<Increment>>', self.on_font_change)
        font_spinbox.bind('<<Decrement>>', self.on_font_change)

        # 创建带滚动条的文本小部件
        text_frame = ttk.Frame(content_frame)
        text_frame.pack(fill=tk.BOTH, expand=True)

        self.content_text = tk.Text(text_frame, wrap=tk.WORD, font=("TkDefaultFont", self.font_size.get()))
        self.content_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 为内容文本添加滚动条
        content_scrollbar = ttk.Scrollbar(text_frame, orient="vertical", command=self.content_text.yview)
        content_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.content_text.configure(yscrollcommand=content_scrollbar.set)

        # 创建语法高亮器
        self.highlighter = LatexHighlighter(self.content_text)

        # 创建上下文菜单 - 移到UI元素创建之后
        self.create_context_menus()

        # 显示欢迎屏幕
        self.show_welcome_screen()

    def create_menu(self):
        """创建应用程序菜单"""
        menu_bar = tk.Menu(self.root)

        # 文件菜单
        file_menu = tk.Menu(menu_bar, tearoff=0)
        file_menu.add_command(label="添加文件", command=self.add_files_dialog)
        file_menu.add_command(label="选择文件夹", command=self.add_folder_dialog)
        file_menu.add_command(label="删除所选", command=self.remove_selected_file)
        file_menu.add_separator()
        file_menu.add_command(label="开始解析", command=self.process_all_files)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        menu_bar.add_cascade(label="文件", menu=file_menu)

        # 视图菜单
        view_menu = tk.Menu(menu_bar, tearoff=0)
        view_menu.add_command(label="刷新", command=self.refresh_view)
        view_menu.add_command(label="展开所有", command=self.expand_all_sections)
        view_menu.add_command(label="折叠所有", command=self.collapse_all_sections)
        view_menu.add_separator()
        view_menu.add_command(label="返回单文件视图", command=self.back_to_single_view)
        menu_bar.add_cascade(label="视图", menu=view_menu)

        # 帮助菜单
        help_menu = tk.Menu(menu_bar, tearoff=0)
        help_menu.add_command(label="关于", command=self.show_about)
        menu_bar.add_cascade(label="帮助", menu=help_menu)

        self.root.config(menu=menu_bar)

    def back_to_single_view(self):
        """返回单文件视图模式"""
        self.search_mode = "single"
        file_selection = self.file_listbox.curselection()
        if file_selection:
            self.display_sections(file_selection[0])
        else:
            self.clear_section_tree()
            self.clear_content()
            if not self.file_manager.files:
                self.show_welcome_screen()

        self.status_var.set("单文件视图模式")

    def create_context_menus(self):
        """创建上下文菜单"""
        # 文件列表上下文菜单
        self.file_context_menu = tk.Menu(self.root, tearoff=0)
        self.file_context_menu.add_command(label="上移", command=lambda: self.move_file(-1))
        self.file_context_menu.add_command(label="下移", command=lambda: self.move_file(1))
        self.file_context_menu.add_separator()
        self.file_context_menu.add_command(label="删除", command=self.remove_selected_file)

        # 为文件列表框设置上下文菜单
        self.file_listbox.context_menu = self.file_context_menu

    def expand_all_sections(self):
        """展开所有章节和小节"""
        for item in self.section_tree.get_children():
            self.section_tree.item(item, open=True)
            for child in self.section_tree.get_children(item):
                self.section_tree.item(child, open=True)

    def collapse_all_sections(self):
        """折叠所有章节和小节"""
        for item in self.section_tree.get_children():
            for child in self.section_tree.get_children(item):
                self.section_tree.item(child, open=False)
            self.section_tree.item(item, open=False)

    def show_welcome_screen(self):
        """显示带有说明的欢迎屏幕"""
        if not self.file_manager.files:
            self.clear_content()

            welcome_text = """
            # 欢迎使用 TeX 文件可视化器

            该应用程序可帮助您可视化和管理 TeX 文件。

            ## 入门指南

            1. 点击"选择文件夹"选择包含特定TeX文件的文件夹
               - 程序将严格按顺序查找并加载以下5个文件：
                 1.tex、2.tex、3.tex、4.tex、conclusion.tex
               - 如果缺少某些文件，程序会给出警告
            2. 或者点击"添加文件"手动选择一个或多个TeX文件
            3. 点击"开始解析"按钮处理所有文件并按顺序编号
            4. 或者选择单个文件查看其章节结构
            5. 点击任意章、节或小节查看其内容

            ## 功能

            - 特定文件处理: 严格加载1.tex、2.tex、3.tex、4.tex和conclusion.tex这5个文件
            - 合并模式: 点击"开始解析"按钮，处理所有文件并按顺序对章节编号
            - 单文件模式: 点击左侧文件列表中的任一文件
            - 逐层解析文档结构：
              * \\chapter 显示为"第i章"
              * \\section 显示为"i.j"编号
              * \\subsection 显示为"i.j.k"编号
            - 搜索特定章节或小节
            - 调整字体大小以获得更好的可读性

            开始使用: 点击"选择文件夹"或"添加文件"按钮！
            """

            self.content_text.insert(tk.END, welcome_text)

            # 应用一些基本的类似markdown的格式
            for pattern, tag in [
                (r'^# .*$', 'h1'),
                (r'^## .*$', 'h2'),
                (r'^- .*$', 'list'),
                (r'^[0-9]+\. .*$', 'numbered')
            ]:
                self.highlight_pattern(pattern, tag)

            # 配置标签
            self.content_text.tag_configure('h1', font=("TkDefaultFont", self.font_size.get() + 4, "bold"))
            self.content_text.tag_configure('h2', font=("TkDefaultFont", self.font_size.get() + 2, "bold"))
            self.content_text.tag_configure('list', lmargin1=20, lmargin2=30)
            self.content_text.tag_configure('numbered', lmargin1=20, lmargin2=40)

    def highlight_pattern(self, pattern, tag):
        """对所有匹配模式的文本应用标签"""
        # 从开始位置开始
        start_pos = "1.0"
        while True:
            # 查找下一个匹配项
            start_pos = self.content_text.search(pattern, start_pos, tk.END, regexp=True)
            if not start_pos:
                break

            # 计算结束位置
            line, col = map(int, start_pos.split('.'))
            line_text = self.content_text.get(f"{line}.0", f"{line}.end")
            match = re.search(pattern, line_text[col:])
            if not match:
                break

            end_pos = f"{line}.{col + match.end()}"

            # 应用标签
            self.content_text.tag_add(tag, start_pos, end_pos)

            # 移动到下一个位置
            start_pos = end_pos

    def add_files_dialog(self):
        """打开文件对话框添加tex文件"""
        files = filedialog.askopenfilenames(
            title="选择TeX文件",
            filetypes=[("TeX文件", "*.tex"), ("所有文件", "*.*")]
        )

        if files:
            added_count, errors = self.file_manager.add_files(files)
            self.update_file_list()

            if errors:
                error_message = "\n".join(errors)
                messagebox.showwarning("文件添加警告", error_message)

            if added_count > 0:
                self.status_var.set(f"已添加 {added_count} 个文件")

                # 添加第一个文件时清除欢迎屏幕
                if len(self.file_manager.files) == added_count:
                    self.clear_content()
            else:
                self.status_var.set("未添加任何文件")

    def add_folder_dialog(self):
        """打开文件夹对话框添加文件夹中的5个特定tex文件"""
        folder = filedialog.askdirectory(
            title="选择包含特定TeX文件的文件夹"
        )

        if folder:
            self.status_var.set("正在处理文件夹...")
            self.root.update()  # 强制更新UI

            added_count, errors = self.file_manager.add_folder(folder)
            self.update_file_list()

            if errors:
                error_message = "\n".join(errors)
                messagebox.showwarning("文件夹处理警告", error_message)

            if added_count > 0:
                if added_count == 5:
                    message = "已成功加载全部5个指定文件"
                else:
                    message = f"已部分加载指定文件 ({added_count}/5)"

                self.status_var.set(message)

                # 清除欢迎屏幕
                self.clear_content()

                # 自动开始解析所有文件
                self.process_all_files()
            else:
                self.status_var.set("未从文件夹加载任何文件")

    def remove_selected_file(self):
        """从列表中删除所选文件"""
        selection = self.file_listbox.curselection()
        if selection:
            index = selection[0]
            file_name = self.file_listbox.get(index)
            self.file_manager.remove_file(index)
            self.update_file_list()
            self.clear_section_tree()
            self.clear_content()
            self.status_var.set(f"已删除文件: {file_name}")

            # 如果没有更多文件，显示欢迎屏幕
            if not self.file_manager.files:
                self.show_welcome_screen()

    def move_file(self, direction):
        """上移或下移所选文件"""
        selection = self.file_listbox.curselection()
        if selection:
            from_index = selection[0]
            to_index = from_index + direction

            if 0 <= to_index < len(self.file_manager.files):
                self.file_manager.move_file(from_index, to_index)
                self.update_file_list()
                self.file_listbox.selection_set(to_index)
                self.status_var.set(f"已将文件移至位置 {to_index + 1}")

    def on_item_reordered(self, event):
        """处理来自拖放的项目重新排序"""
        from_index, to_index = int(event.data[0]), int(event.data[1])
        self.file_manager.move_file(from_index, to_index)
        self.update_file_list()
        self.file_listbox.selection_set(to_index)
        self.status_var.set(f"已将文件移至位置 {to_index + 1}")

    def update_file_list(self):
        """用当前文件更新文件列表框"""
        self.file_listbox.delete(0, tk.END)
        for file_path in self.file_manager.files:
            self.file_listbox.insert(tk.END, os.path.basename(file_path))

    def on_file_select(self, event):
        """处理文件选择"""
        # 如果在合并视图模式，切换回单文件模式
        if self.search_mode == "combined":
            self.search_mode = "single"

        selection = self.file_listbox.curselection()
        if selection:
            index = selection[0]
            file_name = self.file_listbox.get(index)
            self.display_sections(index)
            self.status_var.set(f"已选择文件: {file_name}")
        else:
            self.clear_section_tree()

    def display_sections(self, file_index):
        """显示所选文件的章、节和小节"""
        self.clear_section_tree()

        if file_index < len(self.file_manager.parsed_data):
            file_data = self.file_manager.parsed_data[file_index]

            for i, chapter in enumerate(file_data['chapters']):
                chapter_id = f"chapter-{i}"
                self.section_tree.insert("", "end", iid=chapter_id, text="",
                                         values=(chapter['number'], chapter['name']))

                for j, section in enumerate(chapter['sections']):
                    section_id = f"{chapter_id}-section-{j}"
                    self.section_tree.insert(chapter_id, "end", iid=section_id, text="",
                                             values=(section['number'], section['name']))

                    for k, subsection in enumerate(section['subsections']):
                        subsection_id = f"{section_id}-subsection-{k}"
                        self.section_tree.insert(section_id, "end", iid=subsection_id, text="",
                                                 values=(subsection['number'], subsection['name']))

                    # 如果有小节则展开节
                    if section['subsections']:
                        self.section_tree.item(section_id, open=True)

            # 展开所有章节
            for i in range(len(file_data['chapters'])):
                self.section_tree.item(f"chapter-{i}", open=True)

    def clear_section_tree(self):
        """清除章节树视图"""
        for item in self.section_tree.get_children():
            self.section_tree.delete(item)

    def clear_content(self):
        """清除内容文本视图"""
        self.content_text.delete(1.0, tk.END)

    def process_all_files(self):
        """处理所有文件并显示合并后的章节结构"""
        if not self.file_manager.files:
            messagebox.showinfo("提示", "请先添加一些TeX文件再开始解析")
            return

        # 处理所有文件
        self.status_var.set("正在处理所有文件...")
        self.root.update()  # 强制更新UI

        # 获取处理后的合并数据
        combined_data = self.file_manager.process_all_files()

        # 清除当前树视图
        self.clear_section_tree()

        # 填充树视图
        for i, chapter in enumerate(combined_data['chapters']):
            chapter_id = f"all-chapter-{i}"
            self.section_tree.insert("", "end", iid=chapter_id, text="",
                                     values=(chapter['number'], chapter[
                                         'name'] + f" [{os.path.basename(self.file_manager.files[chapter['file_index']])}]"))

            for j, section in enumerate(chapter['sections']):
                section_id = f"{chapter_id}-section-{j}"
                self.section_tree.insert(chapter_id, "end", iid=section_id, text="",
                                         values=(section['number'], section['name']))

                for k, subsection in enumerate(section['subsections']):
                    subsection_id = f"{section_id}-subsection-{k}"
                    self.section_tree.insert(section_id, "end", iid=subsection_id, text="",
                                             values=(subsection['number'], subsection['name']))

                # 如果有小节则展开节
                if section['subsections']:
                    self.section_tree.item(section_id, open=True)

        # 展开所有章节
        for i in range(len(combined_data['chapters'])):
            self.section_tree.item(f"all-chapter-{i}", open=True)

        self.status_var.set(f"已处理 {len(self.file_manager.files)} 个文件, 共 {len(combined_data['chapters'])} 章")

        # 更新搜索功能以适应新的合并模式
        self.search_mode = "combined"

    def on_section_select(self, event):
        """处理章节选择以显示内容"""
        selection = self.section_tree.selection()
        if not selection:
            return

        selected_id = selection[0]

        # 处理合并视图的选择
        if selected_id.startswith("all-chapter-"):
            combined_data = self.file_manager.process_all_files()
            parts = selected_id.split("-")

            if len(parts) >= 3 and parts[0] == "all" and parts[1] == "chapter":
                chapter_index = int(parts[2])

                if "-section-" not in selected_id and "-subsection-" not in selected_id:
                    # 这是一个章
                    chapter = combined_data['chapters'][chapter_index]
                    self.display_content(chapter['name'], chapter['content'])

                elif "-section-" in selected_id and "-subsection-" not in selected_id:
                    # 这是一个节
                    section_index = int(selected_id.split("-section-")[1])
                    chapter = combined_data['chapters'][chapter_index]
                    section = chapter['sections'][section_index]
                    self.display_content(section['name'], section['content'])

                elif "-subsection-" in selected_id:
                    # 这是一个小节
                    parts = selected_id.split("-subsection-")
                    section_parts = parts[0].split("-section-")
                    section_index = int(section_parts[1])
                    subsection_index = int(parts[1])
                    chapter = combined_data['chapters'][chapter_index]
                    section = chapter['sections'][section_index]
                    subsection = section['subsections'][subsection_index]
                    self.display_content(subsection['name'], subsection['content'])

            return

        # 处理单文件视图的选择
        file_selection = self.file_listbox.curselection()
        if not file_selection:
            return

        file_index = file_selection[0]
        file_data = self.file_manager.parsed_data[file_index]

        if selected_id.startswith("chapter-"):
            # 提取章索引
            if "-section-" not in selected_id and "-subsection-" not in selected_id:
                # 这是一个章
                chapter_index = int(selected_id.split("-")[1])
                self.display_content(file_data['chapters'][chapter_index]['name'],
                                     file_data['chapters'][chapter_index]['content'])
            elif "-section-" in selected_id and "-subsection-" not in selected_id:
                # 这是一个节
                parts = selected_id.split("-section-")
                chapter_index = int(parts[0].split("-")[1])
                section_index = int(parts[1])
                self.display_content(file_data['chapters'][chapter_index]['sections'][section_index]['name'],
                                     file_data['chapters'][chapter_index]['sections'][section_index]['content'])
            elif "-subsection-" in selected_id:
                # 这是一个小节
                parts = selected_id.split("-subsection-")
                section_parts = parts[0].split("-section-")
                chapter_index = int(section_parts[0].split("-")[1])
                section_index = int(section_parts[1])
                subsection_index = int(parts[1])
                self.display_content(
                    file_data['chapters'][chapter_index]['sections'][section_index]['subsections'][subsection_index][
                        'name'],
                    file_data['chapters'][chapter_index]['sections'][section_index]['subsections'][subsection_index][
                        'content'])

    def display_content(self, title, content):
        """在文本视图中显示内容"""
        self.clear_content()

        # 显示标题
        self.content_text.insert(tk.END, f"{title}\n", "title")
        self.content_text.insert(tk.END, "=" * len(title) + "\n\n", "title")

        # 显示内容
        self.content_text.insert(tk.END, content)

        # 应用语法高亮
        self.highlighter.highlight()

        # 配置标签
        self.content_text.tag_configure("title", font=("TkDefaultFont", self.font_size.get() + 2, "bold"))

    def on_search_change(self, *args):
        """处理搜索文本更改"""
        search_text = self.search_var.get().lower()

        # 检查是否在合并模式
        if hasattr(self, 'search_mode') and self.search_mode == "combined":
            self._search_combined_view(search_text)
            return

        if not search_text:
            # 如果搜索为空，刷新视图
            file_selection = self.file_listbox.curselection()
            if file_selection:
                self.display_sections(file_selection[0])
            return

        # 清除并搜索
        self.clear_section_tree()

        file_selection = self.file_listbox.curselection()
        if not file_selection:
            return

        file_index = file_selection[0]
        file_data = self.file_manager.parsed_data[file_index]

        for i, chapter in enumerate(file_data['chapters']):
            chapter_matches = search_text in chapter['name'].lower()
            section_matches = False
            matching_sections = []

            # 检查节是否匹配
            for j, section in enumerate(chapter['sections']):
                section_match = search_text in section['name'].lower()
                subsection_matches = False
                matching_subsections = []

                # 检查小节是否匹配
                for k, subsection in enumerate(section['subsections']):
                    if search_text in subsection['name'].lower():
                        subsection_matches = True
                        matching_subsections.append((k, subsection))

                if section_match or subsection_matches:
                    section_matches = True
                    matching_sections.append((j, section, matching_subsections))

            # 如果章、节或小节匹配则插入
            if chapter_matches or section_matches:
                chapter_id = f"chapter-{i}"
                self.section_tree.insert("", "end", iid=chapter_id, text="",
                                         values=(chapter['number'], chapter['name']))

                # 插入匹配的节
                for j, section, matching_subsections in matching_sections:
                    section_id = f"{chapter_id}-section-{j}"
                    self.section_tree.insert(chapter_id, "end", iid=section_id, text="",
                                             values=(section['number'], section['name']))

                    # 插入匹配的小节
                    for k, subsection in matching_subsections:
                        subsection_id = f"{section_id}-subsection-{k}"
                        self.section_tree.insert(section_id, "end", iid=subsection_id, text="",
                                                 values=(subsection['number'], subsection['name']))

                # 展开章
                self.section_tree.item(chapter_id, open=True)

    def _search_combined_view(self, search_text):
        """在合并视图中搜索章节"""
        combined_data = self.file_manager.process_all_files()

        # 清除树视图
        self.clear_section_tree()

        if not search_text:
            # 如果搜索为空，显示所有章节
            self.process_all_files()
            return

        # 搜索并显示匹配的章节
        for i, chapter in enumerate(combined_data['chapters']):
            chapter_matches = search_text in chapter['name'].lower()
            section_matches = False
            matching_sections = []

            # 检查节是否匹配
            for j, section in enumerate(chapter['sections']):
                section_match = search_text in section['name'].lower()
                subsection_matches = False
                matching_subsections = []

                # 检查小节是否匹配
                for k, subsection in enumerate(section['subsections']):
                    if search_text in subsection['name'].lower():
                        subsection_matches = True
                        matching_subsections.append((k, subsection))

                if section_match or subsection_matches:
                    section_matches = True
                    matching_sections.append((j, section, matching_subsections))

            # 如果章、节或小节匹配则插入
            if chapter_matches or section_matches:
                chapter_id = f"all-chapter-{i}"
                self.section_tree.insert("", "end", iid=chapter_id, text="",
                                         values=(chapter['number'], chapter[
                                             'name'] + f" [{os.path.basename(self.file_manager.files[chapter['file_index']])}]"))

                # 插入匹配的节
                for j, section, matching_subsections in matching_sections:
                    section_id = f"{chapter_id}-section-{j}"
                    self.section_tree.insert(chapter_id, "end", iid=section_id, text="",
                                             values=(section['number'], section['name']))

                    # 插入匹配的小节
                    for k, subsection in matching_subsections:
                        subsection_id = f"{section_id}-subsection-{k}"
                        self.section_tree.insert(section_id, "end", iid=subsection_id, text="",
                                                 values=(subsection['number'], subsection['name']))

                # 展开章
                self.section_tree.item(chapter_id, open=True)

    def on_font_change(self, event):
        """处理字体大小更改"""
        font_size = self.font_size.get()
        self.content_text.configure(font=("TkDefaultFont", font_size))
        # 如果有标题则重新应用标题格式
        self.content_text.tag_configure("title", font=("TkDefaultFont", font_size + 2, "bold"))

        # 更新高亮器的字体
        self.highlighter = LatexHighlighter(self.content_text)
        self.highlighter.highlight()

    def refresh_view(self):
        """刷新当前视图"""
        # 重新解析当前文件
        for i, file_path in enumerate(self.file_manager.files):
            self.file_manager.parsed_data[i] = self.file_manager.parser.parse_file(file_path)

        # 更新显示
        file_selection = self.file_listbox.curselection()
        if file_selection:
            self.display_sections(file_selection[0])

        self.status_var.set("视图已刷新")

    def show_about(self):
        """显示关于对话框"""
        messagebox.showinfo(
            "关于 TeX 可视化器",
            "TeX 文件可视化器\n\n"
            "一个可视化和管理 TeX 文件的工具。\n"
            "允许查看和导航章节和子章节。"
        )


# 主应用程序入口点
def main():
    root = tk.Tk()
    app = TexVisualizerApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()